package net.yuyoo.uusession.web;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;

import net.yuyoo.uusession.core.MemcachedClientProxy;
import net.yuyoo.uusession.core.UUSessionServantInstance;
import net.yuyoo.uusession.support.JsonUtil;
import net.yuyoo.uusession.support.SeqUUIDUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 

/**
 * http session 适配器
 * @author yuyoo (yuyoo4j@163.com)
 * @teme 2010-6-9 下午12:55:59
 */
public class HttpSessionAdapter implements HttpSession {
	
	private static Logger log = LoggerFactory.getLogger(HttpSessionAdapter.class);
	
	/**
	 * 线程池
	 */
	private static ExecutorService threadPool = Executors.newCachedThreadPool();
		
	private String sessionId = null;
	
	private UUSessionServantInstance servant = null;
	
	private HttpSession local = null;
	
	private boolean isNew = false;
	
	private boolean validate = true;
	
	public HttpSessionAdapter(String id, UUSessionServantInstance si, HttpSession hs, boolean create) {
		
		this.sessionId = id;
		this.servant = si;
		this.local = hs;
		if (create) {
			createNewSession();
		} else if (null == sessionId) {
			throw new RuntimeException("不创建新会话情景下,统一会话ID不能为空");
		}
	} 

	public Object getAttribute(String attr) {
		
		if (null == attr || !validate) {
			return null;
		}
		log.debug("获取属性:{}", attr);
		MemcachedClientProxy proxy = servant.getBackendProxy(sessionId);
		String attrCode = Integer.toString(attr.hashCode());
		StringBuilder sb = new StringBuilder(sessionId.length() + attrCode.length() + 1);
		sb.append(sessionId).append('$').append(attrCode);
		String key = sb.toString();
		
		Object rtv = proxy.get(key);
		log.debug("属性key[{}]:{}", key, rtv);
		return rtv;
	}

	@SuppressWarnings("unchecked")
	public Enumeration getAttributeNames() {
		
		if (!validate) {
			return null;
		}
		try {
			MemcachedClientProxy proxy = servant.getBackendProxy(sessionId);
			Map<String, String> attrs = JsonUtil.toBean((String)proxy.get(sessionId), Map.class);
			List an = new ArrayList(attrs.size()); 
			for (String key : attrs.keySet()) {
				String attr = attrs.get(key);
				an.add(an);
			}
			log.debug("枚举所有属性:{}", an);
			return Collections.enumeration(an);
		} catch (Exception ex) {
			throw new RuntimeException("打印属性名称集合异常", ex);
		}
	}

	public long getCreationTime() {				
		Long ct = (Long) getAttribute("creationTime");
		return ct.longValue();
	}

	public String getId() { 
		return sessionId;
	}

	public long getLastAccessedTime() {
		return local.getLastAccessedTime();
	}

	public int getMaxInactiveInterval() { 
		return local.getMaxInactiveInterval();
	}

	public ServletContext getServletContext() { 
		return local.getServletContext();
	}

	public HttpSessionContext getSessionContext() { 
		return local.getSessionContext();
	}

	public Object getValue(String key) { 
		return getAttribute(key);
	}

	public String[] getValueNames() { 
		
		if (!validate) {
			return null;
		}
		try {
			MemcachedClientProxy proxy = servant.getBackendProxy(sessionId);
			Map<String, String> attrs = JsonUtil.toBean((String)proxy.get(sessionId), Map.class);
			String[] vn = new String[attrs.size()];
			int index = 0;
			for (String key : attrs.keySet()) {
				vn[index] = attrs.get(key);
				index++;
			}
			return vn;
		} catch (Exception ex) {
			throw new RuntimeException("打印属性名称集合异常", ex);
		} 
	}

	public void invalidate() { 
		validate = false;
	}

	public boolean isNew() { 
		return isNew;
	}

	public void putValue(String key, Object val) { 
		setAttribute(key, val);
	}

	public void removeAttribute(String attr) {

		if (null == attr || !validate) {
			return;
		}
		try {
			log.debug("删除属性:{}", attr);
			String attrCode = Integer.toString(attr.hashCode());
	
			MemcachedClientProxy proxy = servant.getBackendProxy(sessionId);
			Map<String, String> attrs = JsonUtil.toBean((String)proxy.get(sessionId), Map.class);
			String a = attrs.remove(attrCode);
			if (null != a) {
				proxy.set(sessionId, JsonUtil.toJson(attrs));				
				StringBuilder sb = new StringBuilder(sessionId.length() + attrCode.length() + 1);
				sb.append(sessionId).append('$').append(attrCode);
				String key = sb.toString();
				proxy.delete(key);
			}			
		} catch (Exception ex) {
			throw new RuntimeException("删除属性异常", ex);
		}
	}

	public void removeValue(String key) {
		removeAttribute(key);
	}

	public void setAttribute(String attr, Object val) {
		
		if (null == attr || null == val || !validate) {
			return;
		}
		try {			
			log.debug("保存属性:{}->{}", attr, val);
			String attrCode = Integer.toString(attr.hashCode());
			StringBuilder sb = new StringBuilder(sessionId.length() + attrCode.length() + 1);
			sb.append(sessionId).append('$').append(attrCode);
			String key = sb.toString();
			log.debug("保存key:{}", key);
			MemcachedClientProxy proxy = servant.getBackendProxy(sessionId);
			Map<String, String> attrs = JsonUtil.toBean((String)proxy.get(sessionId), Map.class);
			attrs.put(attrCode, attr);
			
			proxy.set(key, val);
			proxy.set(sessionId, JsonUtil.toJson(attrs));			
		} catch (Exception ex) {
			throw new RuntimeException("保存属性异常", ex);
		}
	}

	public void setMaxInactiveInterval(int mi) { 
		local.setMaxInactiveInterval(mi);
	}

	/**
	 * 创建新会话
	 * @return -- http session 适配器
	 */
	public HttpSessionAdapter createNewSession() {
		
		String sid = SeqUUIDUtil.toSequenceUUID();
		log.debug("创建新会话,原Id[{}]->新ID[{}]", sessionId, sid);
		MemcachedClientProxy proxy = this.servant.getBackendProxy(sid);
		Long current = System.currentTimeMillis();
		String creationTime = "creationTime";
		String attrCode = Integer.toString(creationTime.hashCode());
		StringBuilder sb = new StringBuilder(sid.length() + attrCode.length() + 1);
		sb.append(sid).append('$').append(attrCode);
		String key = sb.toString();
		log.debug("保存创建时间:[{}]->[{}]", key, current);
		proxy.set(key, current);
		Map<String, String> attrs = new HashMap<String, String>();
		attrs.put(Integer.toString(creationTime.hashCode()), creationTime);
		log.debug("保存会话[{}]属性集合:{}", sid, attrs);
		proxy.set(sid, JsonUtil.toJson(attrs));
		
		String oldId = sessionId;
		sessionId = sid;
		delete(oldId);
		isNew = true;
		validate = true;
		return this;
	}
	
	/**
	 * 刷新当前会话
	 */
	public void refresh() {
		refresh(sessionId);
	}
	
	/**
	 * 刷新指定会话
	 * @param sid -- 会话ID
	 */
	public void refresh(String sid) {

		try {
			MemcachedClientProxy proxy = servant.getBackendProxy(sid);
			String attrs = (String) proxy.get(sid);
			if (null != attrs) {
				log.debug("刷新会话[{}],属性集合[{}]", sid, attrs);
				proxy.set(sid, attrs, servant.getMeta().sessionTimeout);
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	/**
	 * 删除指定会话
	 * @param sid -- 会话ID
	 */
	public void delete(final String sid) {
		
		if (null == sid) {
			return;
		}
		Runnable task = new Runnable() {
			public void run() {

				try {
					MemcachedClientProxy proxy = servant.getBackendProxy(sid);
					proxy.delete(sid);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		};
		threadPool.execute(task);
	}
	
	@Override
	public String toString() {

		StringBuilder sb = new StringBuilder();
		sb.append("HttpSessionAdapter{");
		sb.append(" sessionId:").append(sessionId);
		sb.append(", local:").append(local);
		sb.append(", isNew:").append(isNew);
		sb.append(", validate:").append(validate);
		sb.append(", servant:").append(servant);
		sb.append("}");
		return sb.toString();
	}
}
